package com.qf.com.qf.grass.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qf.api.point.dto.PointDTO;
import com.qf.api.point.feign.PointFeignService;
import com.qf.com.qf.grass.mapper.GrassMapper;
import com.qf.com.qf.grass.param.AddGrassParam;
import com.qf.com.qf.grass.param.GrassPageParam;
import com.qf.com.qf.grass.param.UpdateLikeNumParam;
import com.qf.com.qf.grass.service.GrassService;
import com.qf.com.qf.grass.vo.GrassVO;
import com.qf.common.baidu.utils.BaiduTextCheckUtils;
import com.qf.common.core.common.PageVO;
import com.qf.common.core.config.ThreadPoolConfig;
import com.qf.common.core.entity.Grass;
import com.qf.common.core.exception.CustomerException;
import com.qf.common.core.utils.DateUtils;
import com.qf.common.core.utils.UserUtils;
import com.qf.common.es.utils.EsPage;
import com.qf.common.es.utils.EsServiceUtils;
import com.qf.common.minio.utils.MinioUtil;
import com.qf.common.redis.utils.RedisUtil;
import com.qf.common.rocket.utils.RocketMQUtils;
import com.qf.common.xxljob.dto.XxlJobInfoDTO;
import com.qf.common.xxljob.utils.XxlJobUtil;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;


import javax.annotation.Resource;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zdl
 * @date 2025/3/26
 */
@Service
@Slf4j
public class GrassServiceImpl implements GrassService {
    @Resource
    private GrassMapper grassMapper;
    @Resource
    private PointFeignService pointFeignService;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private MinioUtil minioUtil;
    @Resource
    private ThreadPoolConfig threadPoolConfig;
    @Resource
    private XxlJobUtil xxlJobUtil;

    @Resource
    private RocketMQUtils rocketMQUtils;


    @Resource
    private EsServiceUtils esServiceUtils;

    @GlobalTransactional(rollbackFor = Exception.class)
    //@Transactional(rollbackFor = Exception.class)
    @Override
    public void addGrass(AddGrassParam addGrassParam) {
        // 对于文字和图片进行自动审核  百度文本内容审核
        try {
            BaiduTextCheckUtils.textCheck(addGrassParam.getTitle() + addGrassParam.getContent());
        } catch (Exception e) {
            throw new CustomerException("4001", e.getMessage());
        }
        Integer uid = UserUtils.getUser();
        Grass grass = new Grass();
        BeanUtils.copyProperties(addGrassParam, grass);
        grass.setUid(uid);
        // 使用制定分隔符拼接列表数据
        //String imgPath = String.join(",", addGrassParam.getImgList());
        String imgPath = addGrassParam.getImgList().stream().collect(Collectors.joining(","));
        grass.setImgPath(imgPath);
        grassMapper.insert(grass);
        // 将数据同步到es
        threadPoolConfig.taskExecutor().execute(() -> {
            esServiceUtils.insertDocument("qf-article", String.valueOf(grass.getId()), grass);
        });

        // 审核通过 送积分
//        PointDTO pointDTO = new PointDTO();
//        pointDTO.setUid(uid);
//        pointDTO.setPoint(10);
//        pointDTO.setPointType(3);
//        R<?> r = pointFeignService.remoteAddPoint(pointDTO);
//        if (r.getCode() == CommonConstant.FAIL) {
//            throw new CustomerException("4001", r.getMsg());
//        }
        // openfeign调用送积分接口
//        R<?> r = pointFeignService.remoteAddPoint2(3);
//        if (r.getCode() == CommonConstant.FAIL) {
//            throw new CustomerException("4001", r.getMsg());
//        }

//        try {
//            PointMessage message = new PointMessage(uid, 3);
//            producer.sendPoint(message);
//            log.info("发送积分MQ消息成功");
//        }catch (Exception e){
//            log.error("发送积分MQ消息失败", e);
//        }

        // 发送MQ消息
        PointDTO pointDTO = new PointDTO();
        pointDTO.setUid(uid);
        pointDTO.setPoint(10);
        pointDTO.setPointType(3);
        pointDTO.setId(UUID.randomUUID().toString());
        String dto = JSON.toJSONString(pointDTO);
        rocketMQUtils.sendSyncMsg(dto);
        log.info("发送积分MQ消息成功");


    }

    @Override
    public PageVO<GrassVO> grassPage(GrassPageParam pageParam) {
        List<Grass> records = null;
        long total = 0;
        if (StringUtils.hasLength(pageParam.getSearchInfo())) {
            // 使用es搜索
            SearchSourceBuilder builder = new SearchSourceBuilder();
            // 组合条件查
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            boolQueryBuilder.should(QueryBuilders.matchQuery("title", pageParam.getSearchInfo()));
            boolQueryBuilder.should(QueryBuilders.matchQuery("content", pageParam.getSearchInfo()));
            builder.query(boolQueryBuilder);
            // 排序
            builder.sort("createTime", SortOrder.DESC);

            EsPage esPage = esServiceUtils.selectDocumentPage("qf-article", builder, pageParam.getPageNum(), pageParam.getPageSize(), Grass.class);
            records = esPage.getList();
            total = esPage.getTotal();
        } else {
            // 使用mysql分页查询
            Page<Grass> grassPage = new Page<>(pageParam.getPageNum(), pageParam.getPageSize());
            grassPage = grassMapper.selectPage(grassPage, null);
            records = grassPage.getRecords();
            total = grassPage.getTotal();
        }

        Integer uid = UserUtils.getUser();
        // 当天点赞数
        String numKey = String.format("likeNum:%s", DateUtils.date2Str(LocalDate.now(), "yyyyMMdd"));
        List<GrassVO> voList = records.stream().map(item -> {
            GrassVO grassVO = new GrassVO();
            BeanUtils.copyProperties(item, grassVO);
            grassVO.setCoverImg(item.getImgPath().split(",")[0]);
            // hash存点赞记录
            String likeKey = String.format("like:%s", item.getId());
            Integer o = (Integer) redisUtil.hashGet(likeKey, String.valueOf(uid));
            grassVO.setLikeFlag(o == null ? 0 : o);
            Integer o1 = (Integer) redisUtil.hashGet(numKey, String.valueOf(item.getId()));
            grassVO.setLikeNum(o1 == null ? item.getLikeNum() : item.getLikeNum() + o1);
            return grassVO;
        }).collect(Collectors.toList());
        PageVO<GrassVO> pageVO = new PageVO<>();
        pageVO.setTotal(total);
        pageVO.setDataList(voList);
        return pageVO;
    }

    @Override
    public String uploadImg(MultipartFile file) {
        //上传文件名
        String fileName = file.getOriginalFilename();
        String uuid = UUID.randomUUID().toString().replace("-", "");
        fileName = uuid + fileName.substring(fileName.lastIndexOf("."));
        String minioPath = "";
        try {
            minioPath = minioUtil.upload(file.getInputStream(), fileName);
            Grass grass = new Grass();
            grass.setImgPath(minioPath);
            grass.setUid(UserUtils.getUser());
            grassMapper.insert(grass);
        } catch (IOException e) {
            throw new CustomerException("5004", "上传失败");
        }
        return minioPath;

    }

    @Override
    public Grass getGrassById(Integer id) {
        Grass grass = grassMapper.selectById(id);
        return grass;
    }

    @Override
    public void batchUpdateLikeNum() {
        // 获取当天的前一天日期
        LocalDate localDate = LocalDate.now().minusDays(1);
        String key = String.format("likeNum:%s", DateUtils.date2Str(localDate, "yyyyMMdd"));
        Map<Object, Object> map = redisUtil.hashGetAll(key);
        ArrayList<UpdateLikeNumParam> list = new ArrayList<>();
        map.forEach((k, v) -> {
            UpdateLikeNumParam param = new UpdateLikeNumParam();
            param.setGrassId(Integer.parseInt(k.toString()));
            param.setLikeNum(Integer.parseInt(v.toString()));
            if (list.size() >= 100) {
                // 创建新列表提交给线程池（避免共享list）
                List<UpdateLikeNumParam> batchList = new ArrayList<>(list);
                threadPoolConfig.taskExecutor().execute(() -> {
                    grassMapper.batchUpdateLikeNum(batchList);
                });
                list.clear();  // 清空原列表，继续积累下一批
            }
        });

        // 处理剩余数据（同样创建新列表）
        if (!list.isEmpty()) {
            List<UpdateLikeNumParam> finalBatch = new ArrayList<>(list);
            threadPoolConfig.taskExecutor().execute(() -> {
                grassMapper.batchUpdateLikeNum(finalBatch);
            });
        }
    }

    @Override
    public void timerAddGrass(AddGrassParam addGrassParam) {
        // 讲数据添加数据库
        // 对于文字和图片进行自动审核  百度文本内容审核
        try {
            BaiduTextCheckUtils.textCheck(addGrassParam.getTitle() + addGrassParam.getContent());
        } catch (Exception e) {
            throw new CustomerException("4001", e.getMessage());
        }
        Integer uid = UserUtils.getUser();
        Grass grass = new Grass();
        BeanUtils.copyProperties(addGrassParam, grass);
        grass.setUid(uid);
        // 使用制定分隔符拼接列表数据
        //String imgPath = String.join(",", addGrassParam.getImgList());
        String imgPath = addGrassParam.getImgList().stream().collect(Collectors.joining(","));
        grass.setImgPath(imgPath);
        // 获取当前时间
        Date currentTime = new Date();
        // 当前时间是否在定时发布时间之前
        boolean isFuturePublish = addGrassParam.getTimer().after(currentTime);
        grass.setStatus(isFuturePublish ? 0 : 1); // 未来发布=0，立即发布=1
        grassMapper.insert(grass);
        // 只有未来发布才需要创建定时任务 定时发布
        if (isFuturePublish) {
            // 调用定时任务接口
            createPublishJob(grass.getId(), addGrassParam.getTimer());
        }

        /*if (addGrassParam.getTimer().after(currentTime)){
            SimpleDateFormat sdf = new SimpleDateFormat("ss mm HH dd MM ? yyyy");
            String cron = sdf.format(addGrassParam.getTimer());
            // 根据定时时间，调用xxljob中的接口，动态增加定时任务
            XxlJobInfoDTO dto = new XxlJobInfoDTO();
            dto.setExecutorBlockStrategy("SERIAL_EXECUTION");
            dto.setAuthor("zdl");
            dto.setScheduleConf(cron);
            dto.setExecutorRouteStrategy("FIRST");
            dto.setTriggerStatus(0);
            dto.setJobDesc("定时发布笔记");
            dto.setMisfireStrategy("DO_NOTHING");
            dto.setScheduleType("CRON");
            dto.setGlueType("BEAN");
            dto.setExecutorHandler("updateViewEnabledTask");
            xxlJobUtil.addAndStart(dto);
        }*/


    }

    @Override
    public void updateGrassStatus(Integer id, Integer status) {
        // update grass set status = ? where id = ?
        grassMapper.update(null, new LambdaUpdateWrapper<>(Grass.class)
                .eq(Grass::getId, id)
                .set(Grass::getStatus, status));
    }

    /**
     * 创建发布任务的独立方法
     */
    private void createPublishJob(Integer grassId, Date publishTime) {
        XxlJobInfoDTO dto = new XxlJobInfoDTO();

        // 基本任务配置
        dto.setAuthor("zdl");
        dto.setJobDesc("定时发布种草笔记 ID: " + grassId);
        dto.setScheduleType("CRON");
        dto.setMisfireStrategy("DO_NOTHING");
        dto.setExecutorBlockStrategy("SERIAL_EXECUTION");
        dto.setExecutorRouteStrategy("FIRST");

        // 任务处理器配置
        dto.setGlueType("BEAN");
        dto.setExecutorHandler("updateViewEnabledTask");

        // 设置触发时间（转换为cron表达式）
        SimpleDateFormat sdf = new SimpleDateFormat("ss mm HH dd MM ? yyyy");
        dto.setScheduleConf(sdf.format(publishTime));

        // 关键：传递需要发布的笔记ID
        dto.setExecutorParam(String.valueOf(grassId));

        // 创建并立即启用任务
        xxlJobUtil.addAndStart(dto);
    }
}
